home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #49 (Oct 89) / DMP Source / src / pdef0.c < prev    next >
Text File  |  1989-01-02  |  19KB  |  611 lines

  1. /*
  2.  * Draft mode, text-only printing code for the Macintosh.
  3.  */
  4. /*
  5.  * This file is part of the DMP-110 printer driver for the Macintosh
  6.  * series of computers.
  7.  */
  8. /*
  9.  * Earle R. Horton.
  10.  * Wednesday, November 30, 1988
  11.  * All rights reserved.
  12.  */
  13. #include <Windows.h>
  14. #include <Events.h>
  15. #include <Dialogs.h>
  16. #include <Fonts.h>
  17. #include <Memory.h>
  18. #include <Resources.h>
  19. #include <ToolUtils.h>
  20. #include <Errors.h>
  21. #include <OSUtils.h>
  22. #include <Desk.h>
  23. #include "dmp-110.h"
  24. #include "compat.h"
  25.  
  26. #define __SEG__ Main
  27.  
  28. /*
  29.  * Use our own names for these.
  30.  */
  31. #define storage lGParam1
  32. #define pagenum lGParam2
  33. #define PREC    lGParam3
  34. #define picture lGParam4
  35.  
  36. /* Useful constants */
  37. #define SERRESET    8
  38. #define SERSHAKE    10
  39.  
  40. #define XONCR       ((char)17)
  41. #define XOFFCR      ((char)19)
  42. #define RESFILEID   (-8192)
  43.  
  44. OSErr SPOpen();
  45.  
  46. #define WNETrapNumber   0x60
  47. #define UnImpTrapNumber 0x9f
  48. /*
  49.  * Abort printing if command '.' pressed.
  50.  */
  51. checkabort()
  52. {
  53. EventRecord myevent;
  54. Boolean result;
  55. Boolean     WNEisThere = NGetTrapAddress(WNETrapNumber,1) !=
  56.                  NGetTrapAddress(UnImpTrapNumber,1);
  57.  
  58.     if(WNEisThere){
  59.         result = WaitNextEvent(everyEvent,&myevent,0L,0L);
  60.     }else{
  61.         SystemTask();
  62.         result = GetNextEvent(keyDownMask|autoKeyMask, &myevent);
  63.     }
  64.     if(result){
  65.         if(LoWord(myevent.message & charCodeMask) == '.' &&
  66.                   (myevent.modifiers & cmdKey) ){
  67.             PrSetError(iIOAbortErr);                 /* iPrAbort? */
  68.         }
  69.     }
  70. }
  71. /*
  72.  * This function returns a pointer to a specialized GrafPort
  73.  * (a TPrPort) customized for printing.
  74.  *
  75.  * Based on the passed Print Record, we prepare a GrafPort for use
  76.  * by the application in printing.  We store information of use to
  77.  * us in the lGParam[n] fields of the TPrPort.  We use a BitMap
  78.  * whose baseAddr contains a pointer to a buffer whose size is
  79.  * taken from the prXInfo field of the print record.  We define the
  80.  * portRect to correspond to the prInfo.rPage field of the print
  81.  * record.  Later, we will scale the application's drawing commands
  82.  * to fit into the prInfoPT.rPage Rect, and print the Picture which
  83.  * the application has created.
  84.  */
  85.  
  86. pascal TPPrPort myPrOpenDoc(hPrint,pPrPort,pIOBuf)
  87. THPrint     hPrint;
  88. TPPrPort    pPrPort;
  89. Ptr         pIOBuf;
  90. {
  91. TPPrPort    thisport;
  92. Handle      us;
  93. THPrint     savePrint;
  94. BitMap      mybits;
  95. THPrint     ourPrint;
  96. DCtlHandle  d;
  97. DPstorage s;
  98. SysEnvRec World;
  99. short refnum;
  100. /*
  101.  * Allocate storage, abort if no space for TPrPort.
  102.  * First stage aborts if not enough for a TPrPort, setting
  103.  * PrError() to memFullErr and returning nil.
  104.  */
  105.     if(pPrPort == nil){
  106.         if((thisport = (TPPrPort)
  107.             NewPtr((Size)sizeof(TPrPort))) == nil){
  108.             PurgeMem(maxSize);
  109.             thisport = (TPPrPort)NewPtr((Size)sizeof(TPrPort));
  110.             if(thisport == nil){
  111.                 PrSetError(memFullErr);
  112.                 return nil;
  113.             }
  114.         }
  115.         thisport->fOurPtr = TRUE;      /* TRUE: Belongs to printing code. */
  116.     }
  117.     else {
  118.         thisport = pPrPort;
  119.         thisport->fOurPtr = FALSE;      /* FALSE: Belongs to application. */
  120.     }
  121.     thisport->fOurBits = TRUE;
  122. /*
  123.  * If we get here, there is enough space for at least the TPrPort.
  124.  *
  125.  * The next block of code attempts to allocate all the dynamic storage
  126.  * we will need during printing.  If it fails, it sets thisport->storage
  127.  * to nil, and sets PrError() to memFullErr.  The application should detect
  128.  * the print error condition, and call PrCloseDoc.  Dynamic storage which
  129.  * was not allocated successfully is disposed of by PrCloseDoc.  Storage
  130.  * is allocated in several blocks rather than in a single big block in
  131.  * order to facilitate changing the size of the output buffer or band.
  132.  */
  133.     thisport->storage = (long)(s = (DPstorage)NewPtr((Size)sizeof(Dstorage)));
  134.     if(s != nil){
  135.         memset(s,0,sizeof(Dstorage));
  136.         s->obuf = NewPtr((Size)2000);
  137.     }
  138.     ourPrint = hPrint;
  139.     if(HandToHand(&ourPrint) == noErr){
  140.         thisport->PREC = (long)ourPrint;
  141.     }else{
  142.         thisport->PREC = nil;
  143.     }
  144.     thisport->gPort.portBits.baseAddr = mybits.baseAddr = NewPtr((Size)
  145.         ((*hPrint)->prXInfo.iRowBytes*(*hPrint)->prXInfo.iBandV));
  146.     if( (thisport->storage == nil) ||
  147.         (s->obuf == nil) ||
  148.         (thisport->PREC == nil) ||
  149.         (mybits.baseAddr == nil) ){
  150.             PrSetError(memFullErr);
  151.     }else{
  152.  
  153. /*
  154.  * If we get here, then memory worries are over, except of course if we
  155.  * run out while defining a picture.  Don't know what happens then.
  156.  * The TPrPort is ready to be initialized, and the serial port to be
  157.  * opened.  Only possible fatal error remaining is a serial port error.
  158.  */
  159.  
  160.         OpenPort(thisport);
  161.  
  162.         SetStdProcs(&thisport->gProcs);  /* Fill out gProcs for this port. */
  163.         thisport->gPort.grafProcs = &thisport->gProcs;
  164.         SetPort(thisport);
  165.  
  166.         SysEnvirons(1,&World);
  167.         PrSetError(SPOpen(s,&World));
  168.  
  169. /*
  170.  * Save our copy of Print Record Handle, then open the port.
  171.  */
  172.         thisport->PREC = (long)ourPrint;
  173.  
  174. /*
  175.  * Define the port's BitMap as our printing band.
  176.  *
  177.  */
  178.         mybits.bounds.top = 0;
  179.         mybits.bounds.left = 0;
  180.         mybits.bounds.bottom = (*hPrint)->prXInfo.iBandV;
  181.         mybits.bounds.right = (*hPrint)->prXInfo.iBandH+1;
  182.         mybits.rowBytes = (*hPrint)->prXInfo.iRowBytes;
  183.  
  184.         SetPortBits(&mybits);
  185.  
  186.         MovePortTo((*hPrint)->prInfo.rPage.left,(*hPrint)->prInfo.rPage.top);
  187.  
  188.         PortSize((*hPrint)->prInfo.rPage.right-(*hPrint)->prInfo.rPage.left,
  189.                 (*hPrint)->prInfo.rPage.bottom-(*hPrint)->prInfo.rPage.top);
  190.  
  191.         RectRgn(thisport->gPort.visRgn,&thisport->gPort.portRect);
  192.         RectRgn(thisport->gPort.clipRgn,&thisport->gPort.portRect);
  193.  
  194.         thisport->pagenum = 1;
  195.         thisport->storage = (long)s;
  196.         if((*ourPrint)->prJob.pIdleProc == nil)
  197.             (*ourPrint)->prJob.pIdleProc = (ProcPtr)checkabort;
  198. /*
  199.  * Attempt to save Print Record in 'PREC' 1 in the printer file.
  200.  * No big deal if failure, since this is not essential to printing.
  201.  */
  202.         savePrint = (THPrint)GetResource('PREC',1);
  203.         if(savePrint != nil){
  204.             LoadResource(savePrint);
  205.             **savePrint = **ourPrint;
  206.             ChangedResource(savePrint);
  207.             UpdateResFile(HomeResFile(savePrint));
  208.         }
  209.     }
  210.     return thisport;
  211. }
  212. /*
  213.  * Called at completion of a print job, whether successful or not.
  214.  * Clean up any dynamic storage which requires it, then set print
  215.  * error to noErr.
  216.  */
  217. pascal void myPrCloseDoc(pPrPort)
  218. TPPrPort    pPrPort;
  219. {
  220.     DPstorage s;
  221.     if( (pPrPort != nil) &&
  222.         ((s = (DPstorage)pPrPort->storage) != nil) &&
  223.         (s->obuf != nil) &&
  224.         (pPrPort->PREC != nil) &&
  225.         (pPrPort->gPort.portBits.baseAddr != nil) ) {  /* Assume successful open. */
  226.             ClosePort(pPrPort);
  227.             PBClose(&s->iopb,FALSE);
  228.     }
  229.     if(pPrPort != nil){                     /* Dispose of storage which needs it. */
  230.         if(s != nil){
  231.             if(s->obuf != nil){
  232.                 DisposPtr(s->obuf);
  233.             }
  234.             DisposPtr(s);
  235.         }
  236.         if(pPrPort->PREC != nil){
  237.             DisposHandle(pPrPort->PREC);
  238.         }
  239.         if(pPrPort->gPort.portBits.baseAddr != nil){
  240.             DisposPtr(pPrPort->gPort.portBits.baseAddr);
  241.         }
  242.         if(pPrPort->fOurPtr){
  243.              DisposPtr(pPrPort);
  244.         }
  245.     }
  246.     PrSetError(noErr);     /* No bad feelings! */
  247. }
  248. /*
  249.  * This routine opens a new page.  Check for valid TPrPort, then
  250.  * just start a new picture definition.
  251.  */
  252. pascal void myPrOpenPage(pPrPort,pPageFrame)
  253. TPPrPort    pPrPort;
  254. TPRect      pPageFrame;
  255. {
  256. Rect *scalerect;
  257.  
  258.     if(pPageFrame != nil){
  259.         scalerect = pPageFrame;
  260.     }else{
  261.         scalerect = &pPrPort->gPort.portRect;
  262.     }
  263.     SetPort(pPrPort);
  264. /*
  265.  * The application may run out of memory while the picture is being
  266.  * saved.  Don't know how to prevent or even detect this from here.
  267.  */
  268.     pPrPort->picture = (long)OpenPicture(scalerect);
  269. }
  270. /*
  271.  * This is the routine which does the actual printing.
  272.  * Close the picture for the page.  Use DrawPicture() to draw repeatedly,
  273.  * while moving the BitMap down the page to capture an image for each
  274.  * band.
  275.  *
  276.  * Send each band to the output conversion routines.
  277.  */
  278. pascal void myPrClosePage(pPrPort)
  279. TPPrPort    pPrPort;
  280. {
  281. PicHandle thepic;
  282. short   i,iocount,vband,nbands,rows,nleft;
  283. Rect savepr,scaleRect,savebm;
  284. long width,height;
  285. THPrint ourPrint;
  286. char formfeed;
  287. DPstorage s;
  288.  
  289.     ourPrint = (THPrint)pPrPort->PREC;                   /* Set up variables. */
  290.     SetPort(pPrPort);
  291.     ClosePicture();
  292.     thepic = (PicHandle)pPrPort->picture;
  293.     vband = (*ourPrint)->prXInfo.iBandV;
  294.     nbands = (*ourPrint)->prXInfo.iBands;
  295.     s = (DPstorage)pPrPort->storage;
  296.     if(PrError() != noErr){
  297.     }
  298.     else if(setjmp(s->abortbuf) != 0){   /* Pops back here on abort or error. */
  299.         PrSetError(iIOAbortErr);
  300.     }
  301.     else if(pPrPort->pagenum < (*ourPrint)->prJob.iFstPage){/* Check page no. */
  302.         pPrPort->pagenum++;
  303.     }
  304.     else if(pPrPort->pagenum++ > (*ourPrint)->prJob.iLstPage){
  305.         PrSetError(iIOAbortErr);
  306.     } else {
  307.         savepr = pPrPort->gPort.portRect;
  308.         savebm = pPrPort->gPort.portBits.bounds;
  309.  
  310. /*
  311.  * Enlarge portRect of Printing Port.
  312.  */
  313.         OffsetRect(&pPrPort->gPort.portBits.bounds,-savebm.left,-savebm.top);
  314.         scaleRect = (*ourPrint)->prInfoPT.rPage;
  315.         OffsetRect(&scaleRect,-scaleRect.left,-scaleRect.top);
  316.         pPrPort->gPort.portRect = scaleRect;
  317.         RectRgn(pPrPort->gPort.visRgn,&scaleRect);
  318.         RectRgn(pPrPort->gPort.clipRgn,&scaleRect);
  319.  
  320.         rows = scaleRect.bottom - scaleRect.top;
  321.         if((*ourPrint)->prStl.feed != feedCut || waitnextpage()){
  322.             for(i=0;i<rows;i+=vband){                /* Loop over all bands. */
  323.                 MovePortTo(scaleRect.left,-i);              /* Move to next. */
  324.                 EraseRect(&scaleRect);
  325.                 DrawPicture(thepic,&scaleRect);         /* Draw in the band. */
  326.                 dumpbits(pPrPort);                              /* Print it. */
  327.             }
  328.             formfeed = 12;             /* Do a form feed.  Device Dependent. */
  329.             s->iopb.ioParam.ioReqCount = 1;
  330.             s->iopb.ioParam.ioBuffer = &formfeed;
  331.             asyncwrite(s,(*((THPrint)pPrPort->PREC))->prJob.pIdleProc);
  332. /*
  333.  * Restore portRect so Application can draw in it.
  334.  */
  335.             pPrPort->gPort.portBits.bounds = savebm;
  336.             pPrPort->gPort.portRect = savepr;
  337.             RectRgn(pPrPort->gPort.visRgn,&savepr);
  338.             RectRgn(pPrPort->gPort.clipRgn,&savepr);
  339.  
  340.         }else{
  341.              PrSetError(iIOAbortErr);  /* iPrAbort? */
  342.         }
  343.     }
  344.     KillPicture(thepic);
  345. }
  346. dumpbits(pPrPort) /* Dump a printing band to the serial port. */
  347. TPPrPort    pPrPort;
  348. {
  349.     DPstorage s;
  350.     int i,rows;
  351.     BitMap *bits;
  352.     ProcPtr idle;
  353.     s = (DPstorage)pPrPort->storage;
  354.     bits = &pPrPort->gPort.portBits;
  355.     rows = bits->bounds.bottom-bits->bounds.top;
  356.     idle = (*((THPrint)pPrPort->PREC))->prJob.pIdleProc;
  357.     for (i=0;i<rows;i+=16){
  358.         bitmap_to_hires(s,bits,i,rows-i,idle);
  359.         if(PrError() != noErr)return;
  360.     }
  361. }
  362. /*
  363.  * bitmap_to_hires()
  364.  * This function translates a QuickDraw BitMap to codes which may
  365.  * be sent to a Tandy DMP-110 dot-matrix printer in high-resolution
  366.  * graphics mode.  Graphics codes for this printer in hi-res mode
  367.  * include all eight bit characters.  There are two characters for each
  368.  * column of 16 dots on the paper.  The top dot (1) corresponds to bit
  369.  * zero of the first byte sent.  The bottom dot (16) corresponds to bit
  370.  * eight of the second byte.  There are 960 columns, or 1920 bytes, of
  371.  * graphics data to be sent for one line of graphics output.
  372.  * Note that the ToolBox bit manipulation routines use lower-to-upper
  373.  * bit order.
  374.  *
  375.  * No smarts in this routine, the whole 1918 bytes are sent for each
  376.  * line.
  377.  */
  378.  
  379. bitmap_to_hires(s,b,row,nleft,idle)
  380. DPstorage s;
  381. BitMap *b;                          /* BitMap to print. */
  382. int row;                  /* Starting row on this pass. */
  383. int nleft;              /* Max number of rows to print. */
  384. ProcPtr idle;
  385. {
  386.     short *obytes,*inbytes;
  387.     int column,lastcol,nbits,dot;
  388.  
  389.     obytes = (short *)s->obuf;
  390.     for(dot=960;dot-- >0;){
  391.         obytes[dot] = 0;
  392.     }
  393.     lastcol = b->bounds.right - b->bounds.left;
  394.     lastcol = (lastcol > 959) ? 959 : lastcol;
  395.     inbytes = (short *)(b->baseAddr + b->rowBytes*row);
  396.     nbits = b->rowBytes*8;
  397.     for(column=0;column<lastcol;column++){
  398.         (*idle)();
  399.         if(PrError() != noErr)return;
  400.         for(dot=0;dot<8 && dot<nleft;dot++){
  401.             if(BitTst(inbytes,(long)(column+dot*nbits))){
  402.                 BitSet(obytes,(long)(7-dot));
  403.             }
  404.         }
  405.         for(dot=8;dot<16 && dot < nleft;dot++){
  406.             if(BitTst(inbytes,(long)(column+dot*nbits))){
  407.                 BitSet(obytes,(long)(23-dot));
  408.             }
  409.         }
  410.         obytes++;
  411.     }
  412.     output_hires_data(s,(long)(lastcol),idle);  /* Send to printer. */
  413. }
  414. /*
  415.  * output_hires_data() - Send a stream of high resolution graphics data
  416.  * to the Tandy DMP-110.  The codes for transferring the graphics, and
  417.  * for the high-resolution paper advance, are hard-coded into this
  418.  * routine.  Skips blank graphics codes, and repositions the printer
  419.  * head.  The overhead is 8 bytes for repositioning the head and restarting
  420.  * high resolution graphics.  If there are four blank columns, then, we
  421.  * break even.  If there are more, we win.  If there are less than four
  422.  * blank columns, we lose.
  423.  */
  424. output_hires_data(s,columns,idle)
  425. DPstorage s;
  426. long columns;
  427. ProcPtr idle;
  428. {
  429.     unsigned char codes[10];
  430.  
  431.     short *p;
  432.     short pos,ncodes,start;
  433.     short *buf = (short *)s->obuf;
  434.  
  435.  
  436.     for(pos=0,ncodes=0,p=buf,start=0;pos<960;pos++){
  437.         if(buf[pos] == 0){
  438.             if(ncodes != 0){
  439.                 sendcodes(s,p,ncodes,start,idle);
  440.                 if(PrError() != noErr)return;
  441.                 ncodes = 0;
  442.             }
  443.         }else{
  444.             if(ncodes == 0){
  445.                 p = &buf[pos];
  446.                 start = pos;
  447.             }
  448.             ncodes++;
  449.         }
  450.     }
  451.     if(ncodes != 0){
  452.         sendcodes(s,p,ncodes,start,idle);
  453.     }
  454.     codes[0] = 26;               /* DMP-110 carriage return. */
  455.     codes[1] = 27;                    /* High res line feed. */
  456.     codes[2] = 'G';
  457.     s->iopb.ioParam.ioReqCount = 3L;
  458.     s->iopb.ioParam.ioBuffer = (Ptr)codes;
  459.     asyncwrite(s,idle);
  460. }
  461. sendcodes(s,buf,n,pos,idle)
  462. DPstorage s;
  463. char *buf;
  464. int n,pos;
  465. ProcPtr idle;
  466. {
  467.     unsigned char codes[10];
  468.     codes[0] = 27;
  469.     codes[1] = 16;
  470.     codes[2] = (pos>>8)&3;
  471.     codes[3] = pos & 0xFF;
  472.     codes[4] = 27;
  473.     codes[5] = 73;
  474.     codes[6] = (n>>8)&3;
  475.     codes[7] = n&0xFF;
  476.     s->iopb.ioParam.ioReqCount = 8L;
  477.     s->iopb.ioParam.ioBuffer = (Ptr)codes;
  478.     asyncwrite(s,idle);
  479.     s->iopb.ioParam.ioReqCount = (long)(2*n);
  480.     s->iopb.ioParam.ioBuffer = buf;
  481.     asyncwrite(s,idle);
  482. }
  483. /*
  484.  * Modal dialog box: "Insert next sheet."
  485.  */
  486. waitnextpage()
  487. {
  488. DialogPtr sheetdialog;
  489. WindowPtr tempport;
  490. short   itemhit,donetype;
  491. Handle  doneitem;
  492. Rect    donebox;
  493.     if((sheetdialog = GetNewDialog(SHEETDIALOG, 0L,(WindowPtr) -1)) == nil)
  494.         return FALSE;
  495.     InitCursor();
  496.     GetDItem(sheetdialog,DONEITEM,&donetype,&doneitem,&donebox);
  497.     GetPort(&tempport);
  498.     SetPort(sheetdialog);
  499.     PenSize(3,3);
  500.     InsetRect(&donebox,-4,-4);
  501.     FrameRoundRect(&donebox,16,16);
  502.     ModalDialog(0L,&itemhit);
  503.     DisposDialog(sheetdialog);
  504.     SetPort(tempport);
  505.     if(itemhit == STOPITEM) return FALSE;
  506.     return TRUE;
  507. }
  508. /*
  509.  * Open the serial driver and configure it.  Quit if ioResult field
  510.  * of parameter block ever becomes other than noErr.
  511.  */
  512. OSErr SPOpen(s,World)
  513.  
  514. register DPstorage  s;
  515. SysEnvRec   *World;
  516. {
  517. register ParmBlkPtr pb;
  518. int     serconfig;
  519. Pfg     settings;
  520. OSErr   error;
  521. extern char AOutName[],BOutName[];
  522. extern short BaudRates[];
  523.     error = noErr;
  524.     settings = (Pfg)(GetResource('HEXA',RESFILEID));
  525.     if(settings == nil){                /* Where's our stuff? */
  526.         return ResError();
  527.     }
  528.     LoadResource(settings);
  529.     HNoPurge(settings);
  530.     pb = &s->iopb;
  531.     switch (pport){                   /* get the correct port */
  532.         case 0:                                 /* modem port */
  533.             pb->ioParam.ioNamePtr = (StringPtr)AOutName;
  534.             break;
  535.         case 1:                               /* printer port */
  536.             if(IsMPPOpen()){
  537.                 (void)StopAlert(ATALKALERT,nil);
  538.                 return portInUse;
  539.             }
  540.             pb->ioParam.ioNamePtr = (StringPtr)BOutName;
  541.             break;
  542.     }
  543.     PBOpen(pb,FALSE);
  544.     if (pb->ioParam.ioResult != noErr){
  545.          return(pb->ioParam.ioResult);
  546.     }
  547.     pb->ioParam.ioNamePtr = nil;
  548. /*
  549.  * Set up the io parameter block for writing to the serial driver.
  550.  * a control call resets the baud rate.
  551.  * Another sets flow control.
  552.  */
  553.     ((CntrlParam *)pb)->csCode = SERRESET;
  554.     serconfig = data8 + noParity + stop20;
  555.     serconfig += BaudRates[pbaud];
  556.     ((CntrlParam*)pb)->csParam[0] = serconfig;
  557.     PBControl(pb,FALSE);
  558.     if (pb->ioParam.ioResult != noErr) return(pb->ioParam.ioResult);
  559. #define shake ((SerShk *)&((CntrlParam*)pb)->csParam[0])
  560.     shake->errs = FALSE;
  561.     shake->evts = FALSE;
  562.     shake->fDTR = FALSE;
  563.     shake->fInX = FALSE;
  564.     if(XonXoff && (World->machineType >= envMachUnknown)){
  565.         shake->fXOn = TRUE;
  566.         shake->fCTS = FALSE;
  567.         shake->xOn = XONCR;
  568.         shake->xOff = XOFFCR;
  569.     }
  570.     else {
  571.         shake->fXOn = FALSE;
  572.         shake->fCTS = TRUE;
  573.     }
  574.     ((CntrlParam *)pb)->csCode = SERSHAKE;
  575.     PBControl(pb,FALSE);
  576.     if (pb->ioParam.ioResult != noErr) return(pb->ioParam.ioResult);
  577.  
  578.     pb->ioParam.ioPosMode = 0;
  579.     pb->ioParam.ioPosOffset = 0;
  580.     ReleaseResource(settings);
  581.     return(noErr);
  582. }
  583.  
  584. /*
  585.  * Routine to write asynchronously to the serial port, and run an
  586.  * idle procedure while we wait.  The idle routine may call PrSetError(),
  587.  * so we check PrError() for abort each time.  Kill pending serial port
  588.  * IO if abort detected.
  589.  */
  590. asyncwrite(s,idle)
  591. DPstorage s;
  592. ProcPtr idle;
  593. {
  594.     IOParam *p = &(s->iopb.ioParam);
  595.     PBWrite(p,TRUE);                         /* Issue ASYNC write. */
  596.     do{
  597.         (*idle)();                               /* Idle til done. */
  598.         if(PrError() != noErr){                /* Check for abort. */
  599.             if(p->ioResult > 0){                    /* More chars? */
  600.                 PBKillIO(p,FALSE);                 /* Stop output. */
  601.             }
  602.             longjmp(s->abortbuf,1);                    /* Get out. */
  603.         }
  604.     }while(p->ioResult > 0);                /* Check for complete. */
  605.     if(p->ioResult < 0){                     /* Serial port Error! */
  606.         longjmp(s->abortbuf,1);
  607.     }
  608. }
  609.  
  610.  
  611.